package com.mjk.common.core.jdbc.service.plus.wrap;

import com.mjk.common.base.model.BaseEntity;
import com.mjk.common.core.jdbc.annotation.ArcSharding;
import com.mjk.common.core.jdbc.annotation.Transient;
import com.mjk.common.core.jdbc.util.TableUtils;
import com.mjk.common.core.jdbc.util.provider.SqlProvider;
import com.mjk.common.tools.lambada.function.BeeFunction;
import com.mjk.common.util.ObjectUtils;
import com.mjk.common.util.StrUtils;
import lombok.Data;
import lombok.val;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 复杂SQL 查询包装
 */
public class BeeComplexQueryWrapper extends BeeQueryWrapper{
    /**
     * 占位符
     * */
    protected final BeeComplexQueryWrapper complexQueryWrapper = this;

    private List<OutJoin> joins=new ArrayList<>();
    /**
     * 主表别名
     */
    private String mainAlias;

    /**
     * 构造函数接收主表信息
     */
    public BeeComplexQueryWrapper(BaseEntity instance) {
        super(instance);
        select.setLength(0);
        this.mainAlias = instance.getClass().getSimpleName();
    }
    public BeeComplexQueryWrapper(BaseEntity instance, String alias) {
        super(instance);
        select.setLength(0);
        this.mainAlias = alias;
    }

    public BeeComplexQueryWrapper(Class<? extends BaseEntity> instance) {
        super(instance);
        select.setLength(0);
        this.mainAlias = instance.getClass().getSimpleName();
    }

    public BeeComplexQueryWrapper(Class<? extends BaseEntity> instance, String alias) {
        super(instance);
        select.setLength(0);
        this.mainAlias = alias;
    }

    public String getMainAlias() {
        return mainAlias;
    }

    public OutJoin innerJoin(Class<?> clazz, String alias) {
        OutJoin join = new OutJoin(clazz, alias, "join");
        joins.add(join);
        //add2Join(clazz,alias);
        return join;
    }

    public OutJoin leftJoin(Class<?> clazz,String alias){
        OutJoin join = new OutJoin(clazz, alias, "left");
        joins.add(join);
        //add2Join(clazz,alias);
        return join;
    }
    public OutJoin rightJoin(Class<?> clazz,String alias){
        OutJoin join = new OutJoin(clazz, alias, "right");
        joins.add(join);
        //add2Join(clazz,alias);
        return join;
    }

    /**
     * @param alias      a表别名
     * @param clume      a表字段
     * @param otherAlias b表别名
     * @param clume1     b表字段
     * @param <K>
     * @param <H>
     * @return
     */
    public <K extends BaseEntity, H extends BaseEntity> BeeComplexQueryWrapper eqColumn(String alias, BeeFunction<K, ?> clume, String otherAlias, BeeFunction<H, ?> clume1) {
        addCondition(Condition.AND, alias + "." + getFiledName(clume), " = ", otherAlias + "." + getFiledName(clume1));
        return complexQueryWrapper;
    }
    /**
     * 条件相等 a表字段=b表字段
     */
    public <K extends BaseEntity,H extends BaseEntity> BeeComplexQueryWrapper eqColumn(BeeFunction<K, ?> clume,BeeFunction<H, ?> clume1){
        addCondition(Condition.AND,getFiledName(clume)," = ",getFiledName(clume1));
        return complexQueryWrapper;
    }



    private void addCondition(Condition conditionVal,String column,String condition,String column1) {
        if(CollectionUtils.isEmpty(condiations)){
            condiations.add(column + " " + condition + " " + column1);
        }else {
            condiations.add(conditionVal.getConditionVal() + column + " " + condition + " " + column1);
        }
    }

    @Override
    public <T extends BaseEntity> BeeQueryWrapper eq(BeeFunction<T, ?> column, Object val) {
        addCondition(Condition.AND, this.mainAlias + "." + getFiledName(column), "=", val);
        return complexQueryWrapper;
    }

    public <T extends BaseEntity> BeeQueryWrapper eq(BeeFunction<T, ?> column, String alias, Object val) {
        addCondition(Condition.AND, alias + "." + getFiledName(column), "=", val);
        return complexQueryWrapper;
    }

    @Override
    public String toSelect() {
        if (select.isEmpty()) {
            List<String> selects = new ArrayList<>();
            addFields(selects, getInstance().getClass(), mainAlias);
            //添加主表查询数据
            for (OutJoin join : joins) {
                addFields(selects, join.getClazz(), join.alias);
            }
            return StrUtils.join(selects, ",");
        } else {
            return select.toString();
        }
    }

    private List<String> addFields(List<String> selects, Class<?> clazz, String alias) {
        //List<String> selects = new ArrayList<>();
        List<Field> fields = SqlProvider.getValidTableFiled(clazz);
        for (Field f : fields) {
            if (f.getAnnotation(Transient.class) != null) {
                continue;
            }
            String name = SqlProvider.getCloumName(f);
            if (CollectionUtils.isEmpty(selects.stream().filter(item -> item.toLowerCase().contains(name.toLowerCase())).toList())) {
                selects.add(alias + "." + name);
            } else {
                selects.add(alias + "." + name + " as " + alias + name);
            }
        }
        return selects;
    }

    public String toTable() {
        String tableName = TableUtils.getTableName(getInstance());
        if (!ObjectUtils.isEmpty(this.mainAlias)) {
            return tableName + " " + this.mainAlias;
        }
        return tableName;
    }

    public List<String> toJoin() {
        return toOutJoin("join");
    }

    public List<String> toLeftJoin() {
       return toOutJoin("left");
    }

    public List<String> toRightJoin() {
        return toOutJoin("right");
    }

    public List<String> toOutJoin(String type) {
        List<String> tables = new ArrayList<>();
        for(OutJoin join : joins) {
            if (!type.equals(join.getType())){
                continue;
            }
            ArcSharding sharding =join.getClazz().getAnnotation(ArcSharding.class);
            if(null!=sharding) {
                List<String> on = join.getOn();
                if (CollectionUtils.isEmpty(on)) {
                    tables.add(sharding.table() + " " + join.getAlias());
                } else {
                    tables.add(sharding.table() + " " + join.getAlias() + " on " + StrUtils.join(join.getOn(), " and "));
                }
            }
        }
        return tables;
    }

    /**
     * 获取辅助操作中的关联表信息
     * @return
     */
    public List<?> getJoinClass(){
        return this.joins.stream().map(OutJoin::getClazz).toList();
    }

    /**
     * 用于leftjoin 和 rightjoin
     */
    @Data
    public class OutJoin {

        public OutJoin() {

        }

        public OutJoin(Class<?> clazz, String alias, String type) {
            this.clazz = clazz;
            this.alias = alias;
            this.type = type;
        }

        protected final OutJoin join = this;
        /**
         * 实例类
         */
        private Class<?> clazz;
        /**
         * 别名
         */
        private String alias;
        /**
         * 连接类型 left/right/inner
         */
        private String type;
        /**
         * on 条件
         */
        public List<String> on = new ArrayList<>();


        public <K extends BaseEntity,H extends BaseEntity> OutJoin on(BeeFunction<K, ?> clume,BeeFunction<H, ?> clume1) {
            return on(clume, mainAlias, clume1, this.alias);
        }

        public <K extends BaseEntity, H extends BaseEntity> OutJoin on(BeeFunction<K, ?> clume, String mainAlias, BeeFunction<H, ?> clume1, String alias) {
            on.add(mainAlias + "." + complexQueryWrapper.getFiledName(clume) + " = " + alias + "." + complexQueryWrapper.getFiledName(clume1));
            return join;
        }
    }
}
